import { watch, FSWatcher } from 'fs'
import { debounce } from 'lodash'
import { EventEmitter } from 'events'

export interface FileChangeEvent {
  path: string
  content: string
  timestamp: number
}

export class FileWatcherService extends EventEmitter {
  private watchers: Map<string, FSWatcher> = new Map()
  private debounceTime: number = 1000 // 1 second debounce
  private isEnabled: boolean = true

  constructor() {
    super()
  }

  /**
   * Start watching a file for changes
   */
  public watchFile(filePath: string, initialContent: string): void {
    if (!this.isEnabled) return

    // Stop watching if already watching this file
    this.unwatchFile(filePath)

    try {
      const watcher = watch(filePath, { encoding: 'utf8' },
        debounce((eventType) => {
          if (eventType === 'change') {
            this.handleFileChange(filePath)
          }
        }, this.debounceTime)
      )

      this.watchers.set(filePath, watcher)
      console.log(`Started watching file: ${filePath}`)
    } catch (error) {
      console.error(`Failed to watch file ${filePath}:`, error)
    }
  }

  /**
   * Stop watching a file
   */
  public unwatchFile(filePath: string): void {
    const watcher = this.watchers.get(filePath)
    if (watcher) {
      watcher.close()
      this.watchers.delete(filePath)
      console.log(`Stopped watching file: ${filePath}`)
    }
  }

  /**
   * Stop watching all files
   */
  public unwatchAll(): void {
    this.watchers.forEach((watcher, filePath) => {
      watcher.close()
      console.log(`Stopped watching file: ${filePath}`)
    })
    this.watchers.clear()
  }

  /**
   * Enable/disable file watching
   */
  public setEnabled(enabled: boolean): void {
    this.isEnabled = enabled
    if (!enabled) {
      this.unwatchAll()
    }
  }

  /**
   * Set debounce time for file change events
   */
  public setDebounceTime(time: number): void {
    this.debounceTime = time
  }

  /**
   * Get list of currently watched files
   */
  public getWatchedFiles(): string[] {
    return Array.from(this.watchers.keys())
  }

  /**
   * Check if a file is being watched
   */
  public isWatching(filePath: string): boolean {
    return this.watchers.has(filePath)
  }

  private async handleFileChange(filePath: string): Promise<void> {
    try {
      const fs = require('fs').promises
      const content = await fs.readFile(filePath, 'utf8')

      const changeEvent: FileChangeEvent = {
        path: filePath,
        content,
        timestamp: Date.now()
      }

      this.emit('fileChanged', changeEvent)
      console.log(`File changed: ${filePath}`)
    } catch (error) {
      console.error(`Failed to read changed file ${filePath}:`, error)
    }
  }

  /**
   * Cleanup all watchers
   */
  public dispose(): void {
    this.unwatchAll()
    this.removeAllListeners()
  }
}